#include "mcc_generated_files/mcc.h"
//#include "ctype.h"
static CMDS const *clev; // current level

#define MAX_CALL_DEPTH (5)
long depth=0;
int help_depth=0;

int ECL_parser_init( CMDLINE *c, const CMDS *root_level ) {
  int i;
  for(i=0;i<MAXARGS;i++) { 
    c->arg[i]=NULL;
    c->len[i]=0;
  }
  c->nargs=0;
  clev=root_level;
  depth=0;
  return(1);
}

#if 1
int ECL_parse_command( char *line, CMDLINE *c ) {
  int iarg;
  int len, beg;
  beg=0;
  
  iarg=0;
  beg=0;
  for(iarg=0;iarg<MAXARGS;iarg++) {
    len = strcspn(line+beg," \t");
    if(len==0) break;
    c->arg[iarg]=line+beg;
    c->len[iarg]=len;
    beg+=len;
    if(line[beg] == '\0') {
      iarg++;
      break;
    }
    beg+=strspn(line+beg," \t");
    c->arg[iarg][len]=0;
  }
  c->nargs=iarg;
  return(c->nargs);
}
#endif


int ECL_command_help( CMDS const *cptr ) {
  int i;
  CMDS *cp=(CMDS*)cptr;
  while( cp->cmd ) {
    for(i=0;i<help_depth;i++) printf("  ");
    printf("%-12s   %-40s\r\n", cp->cmd, cp->cmd_help);
    if(cp->next) {
      help_depth++;
      //ECL_command_help(cp->next);
      help_depth--;
    }
    cp++;
  }
  return(help_depth);
}


char *ECL_get_prompt( void ) {
  return((char *)(clev->cmd));
}


int ECL_execute_command( int keyc, char *keyv[], int keyl[] ) {
  int clen, len;
  CMDS *cp;

  // handle special permanent commands:

  if(keyc==0) { // just CR was typed
    return(depth);
  } 
  
  if(  (0==strncmp(keyv[0],"help",4))
    || (0==strncmp(keyv[0],"dir",3)) 
    || (0==strncmp(keyv[0],"?",1)) ) {
    if(keyc==1) { // just help on this level)
      cp=(CMDS *)clev->next; 
      while( cp->cmd ) {
        printf("%-12s   %-40s\r\n", cp->cmd, cp->cmd_help);
        cp++;
      }
      return(depth);
    }
#if 0
    else if( (keyc>=2) && (0==strncmp(keyv[1],"all",3))) { // whole command structure
      cp=(CMDS *)clev->next; 
      ECL_command_help(cp);
    }
#endif
  }

  if(0==strncmp(keyv[0],"exit",4)) {
    // printf("Exiting... ");
    if(clev->prev!=NULL) {
      clev=clev->prev;
      return(depth);
    } else {
      return(-1);
    }
  }
#if 1
  cp=(CMDS *)clev->next; // next level, walk through searching for command
  while( cp->cmd ) {
    clen=strlen(cp->cmd); // length of command string
    len=keyl[0];          // length of typed argument string
    if(len > clen) len=clen; // clip if longer
    if(0==strncmp(keyv[0],cp->cmd,len)) {
     //  printf("MATCH:  K:%s:%d, C:%s:%d\r\n", keyv[0],keyl[0], cp->cmd, clen);
      keyc--;
      keyv++;
      keyl++;
#if 1
      if(cp->next) { // this is another list
        clev=cp;
        if(keyc) {
          depth++;
          if(depth>=MAX_CALL_DEPTH) {
            printf("Depth=%ld, too deep, giving up\r\n", depth);
          } else {
           // ECL_execute_command( keyc, keyv, keyl );
          }
          clev=cp->prev;
          keyc++;
          keyv--;
          keyl--;
          depth--;
        }
        break;
      } else 
#endif
      { // this is a command
        cp->CmdHandler( keyc, keyv, keyl );
        break;
      }
    }
    cp++;
  }
#endif
  return(depth);
}

#if 0

int default_silly_func( int keyc, char *keyv[], int keyl[] ) {
  int i;
  int retval;
  uint32_t utest32;
  int32_t itest32;
  double dbltest;
  int igetu32, igeti32, igetdbl;

  printf("num of keys=%d\r\n", keyc);
  for(i=0;i<keyc;i++) {
    igetu32=get_u32( keyv[i], keyl[i], &utest32, 0, 0xffffffff, 88 );
    igeti32=get_i32( keyv[i], keyl[i], &itest32, -100, 0x7fffffff, -1 );
    igetdbl=get_dbl( keyv[i], keyl[i], &dbltest, 0.00L, 9999.99L, 1000.0L );
    printf("%d: val:%s, len=%d.  i32=%ld(%d), u32=%ld(%d), dbl=%lf(%d)\r\n", 
        i, keyv[i], keyl[i], itest32, igeti32,  utest32, igetu32,  dbltest, igetdbl );
  }

  if((keyc>=1) && (0==strncmp(keyv[0], "help", 4))) {
    printf("Detailed Help here...\r\n");
    retval=CMD_SUCCESS;
    return(retval);
  }

  retval=CMD_SUCCESS;
  return(retval);
}
#endif


// Local function define
void strupper( char *str )
{
	while( *str )
	{
		if( *str >= 'a' && *str <= 'z' ) *str -= 0x20;
		str++;
	}
}

char charupper(char ch)
{
	if(ch >= 'a' && ch <= 'z')
		ch -= 0x20;
	
	return ch;
}

uint32_t  Hex2Dec_N( const char *hexBuf, uint8_t size, uint8_t is_hex )
{
	uint32_t 	ret = 0;
	unsigned char	tmp = 0;
	uint32_t	minus = 0;
	const char *	bufStart;

	if( size > 8 ) size = 8; 
	if( hexBuf == NULL ) return (uint32_t)-1;
	
	while ( *hexBuf && (*hexBuf == ' ')) hexBuf++;
	if (*hexBuf == '-') { minus = 1; hexBuf++; }
	else if (*hexBuf == '+') { minus = 0; hexBuf++; }
	bufStart = hexBuf;
	while( *hexBuf )
	{
		if( *hexBuf >= '0' && *hexBuf <= '9' )
			tmp = *hexBuf - '0';
		else if( *hexBuf >= 'A' && *hexBuf <= 'F' )
			tmp = *hexBuf - 'A' + 10;
		else if( *hexBuf >= 'a' && *hexBuf <= 'f' )
			tmp = *hexBuf - 'a' + 10;
		else
			return ret;
			 
		if( ret == 0 )
			ret = tmp;
		else
            if(is_hex == 1)
                ret = (ret << 4) + tmp;
            else
                ret = (ret*10) + tmp;

		hexBuf++;
		if( hexBuf - bufStart >= size )	break;				// max 8 char convert to DEC once a time
	}
	if (minus) ret = -ret;
	return ret;
}


uint8_t IntToChar(int value,char *str,int radix)  
{  
	int sign = 0;
	int i=0;
	int j; 
	char ps[16];
	//memset(ps, 0, 32);
  
	if(value < -0.000001)
	{
		sign = -1;
		value = -value;
	}
	
	do
	{
		if(value%radix > 9)
			ps[i] = value%radix + '0' + 7;
		else
			ps[i] = value%radix + '0';
		
		i++;
	}while((value/=radix) > 0);
	
	if(sign < 0 )
		ps[i] = '-';
	else
		i--;
	
	for(j=i; j>=0; j--)
	{
		str[i-j] = ps[j];
	}
	
	return i;
} 

// format for integer can be decimal or
// hex, using C-language prefix 0x
#define GET_OKAY         (0)
#define GET_FORMAT_ERR   (1)
#define GET_CLIP_MIN     (2)
#define GET_CLIP_MAX     (3)

int get_i32( char *val, int keyl, int32_t *i32, int32_t min, int32_t max, int32_t def ) {
  int32_t temp32;
  *i32=def;
  if(  (keyl>=3) 
    && (   (0==strncmp(val,"0x",2)) 
        || (0==strncmp(val,"0X",2))) ) { //hex format
    val+=2;
    //if(1!=sscanf(val,"%lx", &temp32)) return GET_FORMAT_ERR;
    temp32 = Hex2Dec_N(val, 8, 1);
  } else { // assume decimal format
   // if(1!=sscanf(val,"%ld", &temp32)) return GET_FORMAT_ERR;
    temp32 = Hex2Dec_N(val, 8, 0);
  }
  // candidate value is scanned, now check for limits
  if(temp32<min) {
    *i32=min;
    return GET_CLIP_MIN;
  } else if(temp32>max) {
    *i32=max;
    return GET_CLIP_MAX;
  } else {
    *i32=temp32;
    return GET_OKAY;
  }
}

int get_u32( char *val, int keyl, uint32_t *ui32, uint32_t min, uint32_t max, uint32_t def ) {
  uint32_t temp32;
  *ui32=def;
  if(  (keyl>=3) 
    && (   (0==strncmp(val,"0x",2)) 
        || (0==strncmp(val,"0X",2))) ) { //hex format
    val+=2;
  temp32 = Hex2Dec_N(val, 8, 1);
  } else { // assume decimal format
  temp32 = Hex2Dec_N(val, 8, 0);
  }
  // candidate value is scanned, now check for limits
  if(temp32<min) {
    *ui32=min;
    return GET_CLIP_MIN;
  } else if(temp32>max) {
    *ui32=max;
    return GET_CLIP_MAX;
  } else {
    *ui32=temp32;
    return GET_OKAY;
  }
}

#if 0
int get_dbl( char *val, int keyl, double *dblval, uint32_t dblmin, uint32_t dblmax, uint32_t dbldef ) {
  double dbl;
  *dblval=dbldef;
  //if(1!=sscanf(val,"%lf", &dbl)) return GET_FORMAT_ERR;
  // candidate value is scanned, now check for limits
  if(dbl<dblmin) {
    *dblval=dblmin;
    return GET_CLIP_MIN;
  } else if(dbl>dblmax) {
    *dblval=dblmax;
    return GET_CLIP_MAX;
  } else {
    *dblval=dbl;
    return GET_OKAY;
  }
}
#endif

void Cmd_Handle_Process(void)
{
    int na,k; 
    int i;
	if(huart.new_cmd_flag == 1)
	{
		printf("\r\n");
		// line[icmd++]=CH_RETURN; // terminate command line
		na=ECL_parse_command((char *)huart.cmdline_buf, &cmdline );
		k=ECL_execute_command(na, cmdline.arg, cmdline.len );

		//memset(	(void *)cmdline_buf, 0, sizeof(cmdline_buf));
        for(i=0;i<sizeof(huart.cmdline_buf);i++)
        {
            huart.cmdline_buf[i] = 0;
        }
		printf("%s> ", ECL_get_prompt());			
		huart.new_cmd_flag = 0;	
	}
}


